package app.config;

import app.handler.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


/*
 *  Spring Security配置类
 *
 * 1.它会拿到用户输入的用户名密码；
 *
 * 2.根据用户名通过UserDetailsService 的 loadUserByUsername(username)方法获得一个用户对象；
 *
 * 3.获得一个UserDetails 对象，获得内部的成员属性password；
 *
 * 4.通过PasswordEncoder 的 matches(s1, s2) 方法对比用户的输入的密码和第3步的密码；
 *
 * 5.匹配成功；
 *
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //注入需要的实现类
    @Qualifier("userDetailsServiceImpl")
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private LoginSuccessHandler loginSuccessHandler;
    @Autowired
    private LoginFailHandler loginFailHandler;
    @Autowired
    private NoRightAccessHandler noRightAccessHandler;
    @Autowired
    private NotLoginEntryPoint notLoginEntryPoint;
    @Autowired
    private ReqLogoutSuccessHandler reqLogoutSuccessHandler;

    //覆盖忽略拦截方法
    @Override
    public void configure(WebSecurity web) throws Exception {
        //web.ignoring().antMatchers("/ForgetPassword/**").antMatchers("/Verification/**");
    }

    //定义认证用户信息获取来源、密码校验规则,用户名不存在处理方法
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setHideUserNotFoundExceptions(false);
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //登录配置 制定哪些权限可以访问哪些接口
        http.authorizeRequests()
                //表示访问 这个接口，需要具备 admin 这个角色
                //.antMatchers("/Login/signin").hasRole("ADMIN")
                .antMatchers("/ForgetPassword/**").permitAll()
                .antMatchers("/Register/**").permitAll()
                .antMatchers("/Verification/**").permitAll()
                .antMatchers("/Login/**").permitAll()
                .antMatchers("/QQ/**").permitAll()
                .antMatchers(HttpMethod.POST, "/Login/signIn").hasAuthority("add")
                //表示只接受post请求访问/api/data 需要权限add
                //.antMatchers(HttpMethod.POST, "/api/data").hasAuthority("add")
                //表示只接受get请求访问/api/data 需要权限query
                //.antMatchers(HttpMethod.GET, "/api/data").hasAuthority("query");
                // 跨域预检请求
                //.antMatchers(HttpMethod.OPTIONS,"/**").permitAll()
                // 表示剩余的其他接口，登录之后就能访问
                .anyRequest().authenticated();
        //禁用csrf
        http.csrf().disable();
        //允许跨域，如果springboot/springmvc已有跨域配置，自动采用springboot/springmvc跨域配置
        http.cors();
        //身份验证处理器
        http.httpBasic().authenticationEntryPoint(notLoginEntryPoint);
        //基于token 禁用session
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        /*
         * 1.开启表单登录
         * 2.登录处理接口
         * 3.登录成功处理器
         * 4.登录失败处理器
         */
        http.formLogin().loginProcessingUrl("/Login/signIn").successHandler(loginSuccessHandler).failureHandler(loginFailHandler);
        /*
         * 1.开启注销
         * 2.注销成功处理器
         */
        http.logout().logoutUrl("/Login/logout").logoutSuccessHandler(reqLogoutSuccessHandler).permitAll();
        //访问被拒处理器
        http.exceptionHandling().accessDeniedHandler(noRightAccessHandler);

    }

    //配置用户信息获取来源、密码校验规则
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

    //密码编码器，使用BCrypt加密算法加密
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}